package com.gyy.modbus4j;

import com.serotonin.modbus4j.BatchRead;
import com.serotonin.modbus4j.BatchResults;
import com.serotonin.modbus4j.ModbusFactory;
import com.serotonin.modbus4j.ModbusMaster;
import com.serotonin.modbus4j.code.DataType;
import com.serotonin.modbus4j.exception.ModbusInitException;
import com.serotonin.modbus4j.ip.IpParameters;
import com.serotonin.modbus4j.locator.BaseLocator;

/**
 * @Author gmd
 * @Description modbus通讯，使用modbus4j框架读取slave数据
 * @Date 2021-12-15 14:35:12
 */
public class Modbus4jRead {

    /**
     * 工厂
     */
    public static ModbusFactory modbusFactory = new ModbusFactory();


    /**
     * 获取master
     */
    public static ModbusMaster getMaster() throws ModbusInitException {
        IpParameters params = new IpParameters();
        params.setHost("127.0.0.1");
        params.setPort(502);

        // RTU协议
        // modbusFactory.createRtuMaster(params);
        // UDP协议
        // modbusFactory.createUdpMaster(params);
        // ASCII协议
        // modbusFactory.createAsciiMaster(params);

        // TCP协议
        ModbusMaster master = modbusFactory.createTcpMaster(params, false);
        master.init();

        return master;
    }


    /**
     * 读取Coil线圈开关数据 0x01
     *
     * @param slaveId 从机ID
     * @param offset  需要读取的数据地址
     */
    public static void readCoilStatus(int slaveId, int offset) throws Exception {
        BaseLocator<Boolean> locator = BaseLocator.coilStatus(slaveId, offset);
        Boolean value = getMaster().getValue(locator);
        System.out.println("\nCoils寄存器（0x01）第" + offset + "位数据为：" + value);
    }

    /**
     * 读取DiscreteInputs离散量开关数据 0x02
     *
     * @param slaveId 从机ID
     * @param offset  需要读取的数据地址
     */
    public static void readInputStatus(int slaveId, int offset) throws Exception {
        BaseLocator<Boolean> loc = BaseLocator.inputStatus(slaveId, offset);
        Boolean value = getMaster().getValue(loc);
        System.out.println("\nDiscreteInputs寄存器（0x02）第" + offset + "位数据为：" + value);
    }

    /**
     * 读取HoldingRegisters保持寄存器数据 0x03
     *
     * @param slaveId 从机ID
     * @param offset  需要读取的数据地址
     */
    public static void readHoldingRegister(int slaveId, int offset, int dataType) throws Exception {
        BaseLocator<Number> loc = BaseLocator.holdingRegister(slaveId, offset, dataType);
        Number value = getMaster().getValue(loc);
        System.out.println("\nHoldingRegisters寄存器（0x03）第" + offset + "位数据为：" + value.toString());
    }

    /**
     * 读取InputRegisters输入寄存器数据 0x04
     *
     * @param slaveId 从机ID
     * @param offset  需要读取的数据地址
     */
    public static void readInputRegisters(int slaveId, int offset, int dataType) throws Exception {
        BaseLocator<Number> loc = BaseLocator.inputRegister(slaveId, offset, dataType);
        Number value = getMaster().getValue(loc);
        System.out.println("\nInputRegisters寄存器（0x04）第" + offset + "位数据为：" + value.toString());
    }

    /**
     * 批量读取寄存器数据
     *
     * @param slaveType 寄存器类型（1：读线圈，2：读离散量输入，3：读保持寄存器，4：读输入寄存器）
     * @param slaveId   从机ID
     * @param offset    待读取的数据起始点位
     * @param length    读取数据长度
     * @param dataType  数据类型
     */
    public static void batchReadData(int slaveType, int slaveId, int offset, int length, int dataType) throws Exception {
        switch (slaveType) {
            case 1: {
                ModbusMaster master = getMaster();
                BatchRead batch = null;


                for (int i = offset; i < (offset + length); i++) {
                    batch.addLocator(i, BaseLocator.coilStatus(slaveId, i));
                }
                // 是否连续请求
                batch.setContiguousRequests(false);
                BatchResults<Integer> results = master.send(batch);
                System.out.println("\n批量读取coil（0x01）布尔数据如下：");
                for (int i = 0; i < length; i++) {
                    System.out.println("index=" + (offset + i) + "，value=" + results.getValue(i));
                }
                break;
            }
            case 2: {
                ModbusMaster master = getMaster();
                BatchRead<Integer> batch = new BatchRead<Integer>();
                for (int i = offset; i < (offset + length); i++) {
                    batch.addLocator(i, BaseLocator.inputStatus(slaveId, i));
                }
                // 是否连续请求
                batch.setContiguousRequests(false);
                BatchResults<Integer> results = master.send(batch);
                System.out.println("\n批量读取input（0x02）布尔数据如下：");
                for (int i = 0; i < length; i++) {
                    System.out.println("index=" + (offset + i) + "，value=" + results.getValue(i));
                }
                break;
            }
            case 3: {
                ModbusMaster master = getMaster();
                BatchRead<Integer> batch = new BatchRead<Integer>();
                for (int i = offset; i < (offset + length); i++) {
                    batch.addLocator(i, BaseLocator.holdingRegister(slaveId, i, dataType));
                }
                // 是否连续请求
                batch.setContiguousRequests(false);
                BatchResults<Integer> results = master.send(batch);
                System.out.println("\n批量读取holdingRegister（0x03）数据如下：");
                for (int i = 0; i < length; i++) {
                    System.out.println("index=" + (offset + i) + "，value=" + results.getValue(i));
                }
                break;
            }
            case 4: {
                ModbusMaster master = getMaster();
                BatchRead<Integer> batch = new BatchRead<Integer>();
                for (int i = offset; i < (offset + length); i++) {
                    batch.addLocator(i, BaseLocator.inputRegister(slaveId, i, dataType));
                }
                // 是否连续请求
                batch.setContiguousRequests(false);
                BatchResults<Integer> results = master.send(batch);
                System.out.println("\n批量读取inputRegister（0x04）数据如下：");
                for (int i = 0; i < length; i++) {
                    System.out.println("index=" + (offset + i) + "，value=" + results.getValue(i));
                }
                break;
            }
        }

    }


    public static void main(String[] args) throws Exception {

        //readCoilStatus(1, 0);
        //readInputStatus(2, 0);
        //readHoldingRegister(3, 0, DataType.FOUR_BYTE_FLOAT);
        //readInputRegisters(4, 0, DataType.TWO_BYTE_INT_SIGNED);

        // 批量读取
        batchReadData(3, 3, 0, 9, DataType.FOUR_BYTE_FLOAT);

    }

}
